package manager

import (
	"reflect"
	"github.com/op/go-logging"
	"myPaxos/logger"
	"encoding/json"
)

type Subscription struct {
	ch chan interface{}
}

func CreateSubscription() *Subscription {
	return &Subscription{
		ch: make(chan interface{}, 1),
	}
}

func (sub *Subscription) GetEvent() chan interface{} {
	return sub.ch
}

type Eventhub struct {
	subMap map[interface{}]map[int]*Subscription
	logger *logging.Logger
}

func NewEventhub() *Eventhub {
	eh :=  &Eventhub{
		subMap: make(map[interface{}]map[int]*Subscription),
		logger: logger.GetLogger("Eventhub"),
	}
	eh.init()
	return eh
}

func (eh *Eventhub) init() {
	//TODO: init event subscriptions
}

func (eh *Eventhub) Subscribe(label int, events ...interface{}) *Subscription {
	sub := CreateSubscription()
	for _,ev := range events {
		m := eh.subMap[reflect.TypeOf(ev)]
		if m != nil {
			if m[label] != nil {
				eh.logger.Errorf("the label has already exist, ignore this sub")
				continue
			}
			eh.subMap[reflect.TypeOf(ev)][label] = sub
		} else {
			eh.subMap[reflect.TypeOf(ev)] = make(map[int]*Subscription)
			eh.subMap[reflect.TypeOf(ev)][label] = sub
		}
	}
	return sub
}

func (eh *Eventhub) Post(ev interface{}) {
	for _,sub := range eh.subMap[reflect.TypeOf(ev)] {
		event := &Event {
			Data: ev,
		}
		sub.ch <- event
	}
}

func (eh *Eventhub) PostWrapper(ev interface{}, typ int) {
	switch typ {
	case Vote_Wrapper:
		voteWrapper := ev.(*VoteWrapper)
		switch voteWrapper.Type {
		case Vote_Event:
			vote := &Vote{}
			err := json.Unmarshal(voteWrapper.Payload, vote)
			if err != nil {
				eh.logger.Errorf("unmarshal Vote event error: %s", err.Error())
			} else {
				eh.Post(vote)
			}
		//TODO: add other events here
		default:
			eh.logger.Errorf("unsupported type in Vote_Wrapper type: %d", voteWrapper.Type)
		}
	case Msg_Wrapper:
		msgWrapper := ev.(*MsgWrapper)
		switch msgWrapper.Type {
		case Msg_Proposal:
			proposal := &Propose{}
			err := json.Unmarshal(msgWrapper.Payload, proposal)
			if err != nil {
				eh.logger.Errorf("unmarshal Vote event error: %s", err.Error())
			} else {
				eh.Post(proposal)
			}
		//TODO: add other events here
		default:
			eh.logger.Errorf("unsupported type in Vote_Wrapper type: %d", msgWrapper.Type)
		}
	}

}
